package lib4wrapper;

import socket.AbstractTCP;
import socket.CmdMessage;
import socket.CmdMsgType;
import socket.TCP;
import struct.ResourceConfig;
import util.Util;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import java.io.IOException;
import java.net.Socket;

public class WrapperRemoteConnector {
    private static WrapperRemoteConnector instance;
    private TCP tcp = null;
    private Log logger = LogFactory.getLog(WrapperRemoteConnector.class);
    private String wrapperName;
    
    private WrapperRemoteConnector() {
    }

    public Log getLogger() {
        return logger;
    }
    
    public static WrapperRemoteConnector getInstance() {
        if (instance == null) {
            synchronized (WrapperRemoteConnector.class) {
                if (instance == null) {
                    instance = new WrapperRemoteConnector();
                }
            }
        }
        return instance;
    }

    public CmdMessage recv() {
        String recv = tcp.recv();
        if (recv != null) {
            CmdMessage recvCmd = new CmdMessage(recv);
            if (!recvCmd.cmd.equalsIgnoreCase(CmdMsgType.ALIVE_REQUEST)){
                logger.info(String.format("[%s]: recv() -> %s", wrapperName, recv));
            }
            return new CmdMessage(recv);
        }
        logger.info(String.format("[%s]: recv() -> null", wrapperName));
        return null;
    }

    public void send(CmdMessage msg) {
        tcp.send(msg.toString());
        logger.info(String.format("[%s]: send(%s)", wrapperName, msg));
    }

    public void close() {
        shutdown();
    }

    public class WrapperRemoteConnectorTCP extends AbstractTCP {
        public WrapperRemoteConnectorTCP(Socket socket, boolean lockFlag) {
            super(socket, lockFlag);
        }

        public WrapperRemoteConnectorTCP(Socket socket) {
            super(socket);
        }

        @Override
        public void close() {
            try {
                socket.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        @Override
        public void callback() {
            logger.info(String.format("[%s]: TCP connection is broken.", wrapperName));
        }
    }

    public boolean register(String ip, int port, ResourceConfig resourceConfig) {
        wrapperName = resourceConfig.name;
        Util.configLog4j();

        CmdMessage send = new CmdMessage(CmdMsgType.REGISTER, resourceConfig.toString());
        boolean state = false;
        try {
            tcp = new WrapperRemoteConnectorTCP(new Socket(ip, port), false);
            tcp.send(send.toString());

            String recv = tcp.recv();
            if (recv != null) {
                CmdMessage recvCmd = new CmdMessage(recv);
                if (recvCmd.cmd.equals(CmdMsgType.REGISTER_BACK)) {
                    state = Boolean.parseBoolean(recvCmd.message);
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
            tcp.close();
        }
        logger.info(String.format("[%s]: register(%s, %d, %s) -> %b", wrapperName, ip, port, resourceConfig, state));
        return state;
    }

    public boolean shutdown() {
        tcp.close();
        logger.info(String.format("[%s]: shutdown()", wrapperName));
        return true;
    }
}
